package com.rrd.hive.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.ql.udf.xml.UDFXPathUtil;
import org.apache.hadoop.io.Text;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


@Description(
        name = "xpath_nodes",
        value = "_FUNC_(xml, xpath, split='-|-') - Evaluates a list xpath expression",
        extended = "Example:\n> SELECT _FUNC_('<a><b>1</b><c>2</c></a>','a'); \n  <b>1</b>-|-<c>2</c>\n> SELECT _FUNC_('<a><b>1</b></a>','a');\n  1"
)

public class UDFXPathNodesPlus extends UDF {

    private final UDFXPathUtil xpath = new UDFXPathUtil();

    public UDFXPathNodesPlus() {
    }


    public List<Text> evaluate(String xml, String path, String split) throws TransformerException {
        if (xml == null || path == null) {
            return null;
        }
        ArrayList<Text> result = new ArrayList();

        Node node = xpath.evalNode(xml, path);
        if (node != null){
            NodeList middleNodes = node.getChildNodes();
            for (int i = 0; i < middleNodes.getLength(); i++) {
                Node middleNode = middleNodes.item(i);
                String name = middleNode.getNodeName();
                NodeList childNodes = middleNode.getChildNodes();
                if (childNodes.getLength() > 0){
                    for (int j = 0; j < childNodes.getLength(); j++) {
                        Node childNode = childNodes.item(j);
                        String childName = childNode.getNodeName();
                        result.add(new Text(name + split + childName + split + toString(childNode)));
                    }
                } else {
                    result.add(new Text(name + split + "null" + split + toString(middleNode)));
                }
            }
        }
        if (result.size() == 0){
            result.add(new Text(""));
        }
        return result;
    }

    public List<Text> evaluate(String xml, String path) throws TransformerException {
        String split = "-|-";
        return evaluate(xml, path, split);
    }

    private static String toString(Node n) throws TransformerFactoryConfigurationError, TransformerException {
        String value = null;
        if (n.getChildNodes().getLength() == 0 && n.getNodeType() == Node.ELEMENT_NODE) {
            value = "";
        } else if (n.getChildNodes().getLength() == 1 && n.getFirstChild().getNodeType() == Node.TEXT_NODE) {
            value = n.getFirstChild().getNodeValue();
        }
        if (value == null) {
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            StreamResult result = new StreamResult(new StringWriter());
            DOMSource source = new DOMSource(n);
            transformer.transform(source, result);
            value = result.getWriter().toString().replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "");
        }
        return value;
    }

    public static void main(String[] args) throws IOException, TransformerException {
//        StringBuffer sb = new StringBuffer();
//        readToBuffer(sb, "/Users/jx/Downloads/a.xml");
        String xml = "<feature><standard><a><b/></a></standard></feature>";
        long start=System.currentTimeMillis();   //获取开始时间
        List<Text> l1 = new UDFXPathNodesPlus().evaluate(xml, "feature/standard");
        long end=System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间： "+(end-start)+"ms");
        System.out.println(l1);
        for (Text a: l1) {
            System.out.println(a);
        }
    }

    public static void readToBuffer(StringBuffer buffer, String filePath) throws IOException {
        InputStream is = new FileInputStream(filePath);
        String line; // 用来保存每行读取的内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        line = reader.readLine(); // 读取第一行
        while (line != null) { // 如果 line 为空说明读完了
            buffer.append(line); // 将读到的内容添加到 buffer 中
            buffer.append("\n"); // 添加换行符
            line = reader.readLine(); // 读取下一行
        }
        reader.close();
        is.close();
    }

}